home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Copyright (C) 1994, Enterprise Integration Technologies Corp.
- ** All Rights Reserved.
- ** Kevin Hughes, kevinh@eit.com
- ** 7/31/94
- */
-
- #include "hypermail.h"
- #include "parse.h"
-
- /* Parsing...the heart of Hypermail!
- ** This loads in the articles from stdin or a mailbox, adding the right
- ** field variables to the right structures. If readone is set, it will
- ** think anything it reads in is one article only.
- */
-
- void loadheaders(mbox, use_stdin, readone)
- char *mbox;
- int use_stdin;
- int readone;
- {
- FILE *fp;
- char name[NAMESTRLEN], email[MAILSTRLEN], date[DATESTRLEN],
- msgid[MSGDSTRLEN], subject[SUBJSTRLEN], inreply[REPYSTRLEN],
- line[MAXLINE], tmpfrom[MAXLINE], fromdate[DATESTRLEN],
- oldline[MAXLINE];
- int num, isinheader, hassubject, hasdate, wasinreply;
- struct body *bp;
-
- if (!strcmp(mbox, "NONE") || use_stdin)
- fp = stdin;
- else {
- if ((fp = fopen(mbox, "r")) == NULL) {
- sprintf(errmsg, "Couldn't open mail archive \"%s\".",
- mbox);
- progerr(NULL);
- }
- }
-
- if (readone)
- num = bignum;
- else
- num = 0;
- hassubject = 0;
- hasdate = 0;
- wasinreply = 0;
- isinheader = 1;
- inreply[0] = '\0';
- tmpfrom[0] = '\0';
- oldline[0] = '\0';
- bp = NULL;
- if (!readone) {
- replylist = NULL;
- subjectlist = NULL;
- authorlist = NULL;
- datelist = NULL;
- }
- if (showprogress && readone)
- printf("Reading new header...\n");
- if (showprogress && !readone) {
- if (!strcmp(mbox, "NONE") || use_stdin)
- printf("Loading mailbox... ");
- else
- printf("Loading mailbox \"%s\"... ", mbox);
- }
- while (fgets(line, MAXLINE, fp) != NULL) {
- if (isinheader) {
- if (!strncmp(line, "Received:", 9) ||
- !strncmp(line, "Return-Path:", 12) ||
- !strncmp(line, "Cc:", 3) ||
- !strncmp(line, "X-", 2) ||
- !strncmp(line, "Flags:", 6))
- continue;
- if (!strncmp(line, "From ", 5))
- strcpy(fromdate, (char *) getfromdate(line));
- else if (!strncmp(line, "Date:", 5)) {
- bp = (struct body *) addbody(bp, line);
- strcpy(date, (char *) getmaildate(line));
- hasdate = 1;
- }
- else if (!strncmp(line, "From:", 5)) {
- bp = (struct body *) addbody(bp, line);
- getname(line, name, email);
- }
- else if (!strncmp(line, "Message-Id:", 11)) {
- bp = (struct body *) addbody(bp, line);
- strcpy(msgid, (char *) getid(line));
- }
- else if (!strncmp(line, "Subject:", 8)) {
- bp = (struct body *) addbody(bp, line);
- strcpy(subject, (char *) getsubject(line));
- hassubject = 1;
- }
- else if (!strncmp(line, "In-Reply-To:", 12)) {
- bp = (struct body *) addbody(bp, line);
- strcpy(inreply, (char *) getreply(line));
- wasinreply = 1;
- }
- else if ((!strncmp(line, " ", 4) ||
- line[0] == '\t') &&
- strchr(line, '<') && strchr(line, '>') &&
- strchr(line, '@') && wasinreply) {
- bp = (struct body *) addbody(bp, line);
- strcpy(inreply, (char *) getreply(line));
- wasinreply = 0;
- }
- else if (!strncmp(line, "To:", 3))
- bp = (struct body *) addbody(bp, line);
- else if (line[0] == '\n') {
- bp = (struct body *) addbody(bp, line);
- isinheader = 0;
- }
- }
- else {
- if (!strncmp(line, "From ", 5)) {
- if (readone)
- continue;
- if (strstr(oldline,
- "Forwarded message:")) {
- oldline[0] = '\0';
- continue;
- }
- isinheader = 1;
- wasinreply = 0;
- if (!hassubject)
- strcpy(subject, NOSUBJECT);
- else
- hassubject = 1;
- if (!hasdate)
- strcpy(date, NODATE);
- else
- hasdate = 1;
- if (inreply[0] == '\0')
- oneunre(inreply, subject);
- while (rmlastlines(bp));
- addhash(num, date, name, email, msgid, subject,
- inreply, fromdate, bp);
- authorlist = (struct header *)
- addheader(authorlist, num, name, subject,
- date, 1);
- subjectlist = (struct header *)
- addheader(subjectlist, num, name, unre(subject),
- date, 0);
- datelist = (struct header *)
- addheader(datelist, num, name, subject,
- fromdate, 2);
- strcpy(fromdate, (char *) getfromdate(line));
-
- bp = NULL;
- num++;
-
- if (!(num % 10) && showprogress && !readone) {
-
- #ifdef RISCOS
- printf("%4d,", num);
- #else
- printf("\b\b\b\b%4d", num);
- #endif
- fflush(stdout);
- }
- inreply[0] = '\0';
- }
- else
- bp = (struct body *) addbody(bp, line);
- }
- strcpy(oldline, line);
- }
- if (!isinheader) {
- if (!hassubject)
- strcpy(subject, NOSUBJECT);
- if (!hasdate)
- strcpy(date, NODATE);
- if (inreply[0] == '\0')
- oneunre(inreply, subject);
- while (rmlastlines(bp));
- addhash(num, date, name, email, msgid, subject, inreply,
- fromdate, bp);
- authorlist = (struct header *)
- addheader(authorlist, num, name, subject, date, 1);
- subjectlist = (struct header *)
- addheader(subjectlist, num, name, unre(subject), date, 0);
- datelist = (struct header *) addheader(datelist, num, name,
- subject, fromdate, 2);
- num++;
- }
- if (showprogress && !readone)
-
- #ifdef RISCOS
- printf("%4d articles.\n", num);
- #else
- printf("\b\b\b\b%4d articles.\n", num);
- #endif
-
- if (!readone)
- bignum = num - 1;
- fclose(fp);
-
- crossindex();
-
- threadlist = NULL;
- printedthreadlist = NULL;
- crossindexthread1(datelist);
- }
-
- /* All this does is get all the relevant header information from the
- ** comment fields in existing archive files. Everything is loaded into
- ** structures in the exact same way as if articles were being read from
- ** stdin or a mailbox.
- */
-
- void loadoldheaders(dir)
- char *dir;
- {
- FILE *fp;
- char name[NAMESTRLEN], email[MAILSTRLEN], date[DATESTRLEN],
- msgid[MSGDSTRLEN], subject[SUBJSTRLEN], inreply[REPYSTRLEN],
- line[MAXLINE], fromdate[DATESTRLEN], filename[MAXFILELEN];
- int num;
- struct body *bp;
-
- num = 0;
- sprintf(filename, "%s%s%.4d.html", dir,
- (dir[strlen(dir) - 1] == '/') ? "" : "/", num);
-
- bp = NULL;
- bp = (struct body *) addbody(bp, "\0");
-
- authorlist = subjectlist = datelist = NULL;
-
- if (showprogress)
- printf("Reading old headers... ");
- while ((fp = fopen(filename, "r")) != NULL) {
-
- fgets(line, MAXLINE, fp);
- strcpy(fromdate, (char *) getvalue(line));
- fgets(line, MAXLINE, fp);
- strcpy(date, (char *) getvalue(line));
- fgets(line, MAXLINE, fp);
- strcpy(name, (char *) getvalue(line));
- fgets(line, MAXLINE, fp);
- strcpy(email, (char *) getvalue(line));
- fgets(line, MAXLINE, fp);
- strcpy(subject, (char *) unconvchars(getvalue(line)));
- fgets(line, MAXLINE, fp);
- strcpy(msgid, (char *) getvalue(line));
- fgets(line, MAXLINE, fp);
- strcpy(inreply, (char *) unconvchars(getvalue(line)));
-
- fclose(fp);
-
- addhash(num, date, name, email, msgid, subject,
- inreply, fromdate, bp);
- authorlist = (struct header *)
- addheader(authorlist, num, name, subject, date, 1);
- subjectlist = (struct header *)
- addheader(subjectlist, num, name, unre(subject), date, 0);
- datelist = (struct header *)
- addheader(datelist, num, name, subject, fromdate, 2);
-
- num++;
- if (!(num % 10) && showprogress) {
-
- #ifdef RISCOS
- printf("%4d", num);
- #else
- printf("\b\b\b\b%4d", num);
- #endif
- fflush(stdout);
- }
-
- sprintf(filename, "%s%s%.4d.html", dir,
- (dir[strlen(dir) - 1] == '/') ? "" : "/", num);
- }
- if (showprogress)
-
- #ifdef RISCOS
- printf("%4d articles.\n", num);
- #else
- printf("\b\b\b\b%4d articles.\n", num);
- #endif
-
- if (!num)
- bignum = 0;
- else
- bignum = num;
- }
-
- /* Adds a "Next:" link in the proper article, after the archive has been
- ** incrementally updated.
- */
-
- void fixnextheader(dir, num)
- char *dir;
- int num;
- {
- char filename[MAXFILELEN], line[MAXLINE], name[NAMESTRLEN],
- email[MAILSTRLEN], subject[SUBJSTRLEN], inreply[REPYSTRLEN],
- date[DATESTRLEN], fromdate[DATESTRLEN], msgid[MSGDSTRLEN];
- struct body *bp, *status;
- FILE *fp;
-
- sprintf(filename, "%s%s%.4d.html", dir,
- (dir[strlen(dir) - 1] == '/') ? "" : "/", num);
-
- bp = NULL;
- if ((fp = fopen(filename, "r")) != NULL) {
- while ((fgets(line, MAXLINE, fp)) != NULL)
- bp = (struct body *) addbody(bp, line);
- }
- else
- return;
- fclose(fp);
-
- if ((fp = fopen(filename, "w+")) != NULL)
- while (bp != NULL) {
- fprintf(fp, "%s", bp->line);
- if (!strncmp(bp->line, "<!-- next=", 10)) {
-
- status = (struct body *) hashnumlookup(num + 1,
- name, email, subject, inreply, date, fromdate,
- msgid);
- if (status != NULL) {
- fprintf(fp, "<li> <b>Next message:</b> ");
- fprintf(fp,
- "<a href=\"%.4d.html\">%s: \"%s\"</a>\n",
- num + 1, name, convchars(subject));
- }
-
- }
- bp = bp->next;
- }
- fclose(fp);
- }
-
- /* Adds a "Reply:" link in the proper article, after the archive has been
- ** incrementally updated.
- */
-
- void fixreplyheader(dir, num)
- char *dir;
- int num;
- {
- int replynum, subjmatch;
- char filename[MAXFILELEN], line[MAXLINE], name[NAMESTRLEN],
- email[MAILSTRLEN], subject[SUBJSTRLEN], inreply[REPYSTRLEN],
- date[DATESTRLEN], fromdate[DATESTRLEN], msgid[MSGDSTRLEN],
- name2[NAMESTRLEN], subject2[SUBJSTRLEN];
- struct body *bp, *status;
- FILE *fp;
-
- status = (struct body *) hashnumlookup(num,
- name, email, subject, inreply, date, fromdate, msgid);
- if (status == NULL || inreply[0] == '\0')
- return;
- if (inreply[0] != '\0') {
- replynum = hashreplylookup(inreply, name2, subject2,
- &subjmatch);
- if (replynum == -1)
- return;
- }
-
- sprintf(filename, "%s%s%.4d.html", dir,
- (dir[strlen(dir) - 1] == '/') ? "" : "/", replynum);
-
- bp = NULL;
- if ((fp = fopen(filename, "r")) != NULL) {
- while ((fgets(line, MAXLINE, fp)) != NULL)
- bp = (struct body *) addbody(bp, line);
- }
- else
- return;
- fclose(fp);
-
- if ((fp = fopen(filename, "w+")) != NULL)
- while (bp != NULL) {
- if (!strncmp(bp->line, "<!-- reply", 10)) {
- fprintf(fp, "<li> <b>Reply:</b> ");
- fprintf(fp, "<a href=\"%.4d.html\">", num);
- fprintf(fp, "%s: \"%s\"</a>\n",
- name, convchars(subject));
- }
- fprintf(fp, "%s", bp->line);
- bp = bp->next;
- }
- fclose(fp);
- }
-
- /* Adds a "Next in thread:" link in the proper article, after the archive
- ** has been incrementally updated.
- */
-
- void fixthreadheader(dir, num)
- char *dir;
- int num;
- {
- int threadnum;
- char filename[MAXFILELEN], line[MAXLINE], name[NAMESTRLEN],
- subject[SUBJSTRLEN];
- struct body *bp;
- struct reply *rp;
- FILE *fp;
-
- for (rp = threadlist; rp != NULL; rp = rp->next)
- if (rp->next != NULL && rp->next->msgnum == num &&
- rp->msgnum != -1) {
- threadnum = rp->msgnum;
- strcpy(name, rp->next->name);
- strcpy(subject, rp->next->subject);
- break;
- }
- if (rp == NULL)
- return;
-
- sprintf(filename, "%s%s%.4d.html", dir,
- (dir[strlen(dir) - 1] == '/') ? "" : "/", threadnum);
-
- bp = NULL;
- if ((fp = fopen(filename, "r")) != NULL) {
- while ((fgets(line, MAXLINE, fp)) != NULL)
- bp = (struct body *) addbody(bp, line);
- }
- else
- return;
- fclose(fp);
-
- if ((fp = fopen(filename, "w+")) != NULL)
- while (bp != NULL) {
- fprintf(fp, "%s", bp->line);
- if (!strncmp(bp->line, "<!-- nextthr", 12)) {
- fprintf(fp, "<li> <b>Next in thread:</b> ");
-
- #ifdef RISCOS
-
- fprintf(fp, "<a href=\"file://%s/%s/%.4d/%.4d\">",
- HOST, FILEDIR, num/FPD, num);
- fprintf(fp, "%s: \"%s\"</a>\n",
- name, convchars(subject));
-
- #else
- fprintf(fp, "<a href=\"%.4d.html\">", num);
- fprintf(fp, "%s: \"%s\"</a>\n",
- name, convchars(subject));
- #endif
-
- }
- bp = bp->next;
- }
- fclose(fp);
- }
-
- /* Cross-indexes - adds to a list of replies. If a message is a reply to
- ** another, the number of the messge it's replying to is added to the list.
- ** This list is searched upon printing.
- */
-
- void crossindex()
- {
- int num, status, maybereply;
- char name[NAMESTRLEN], subject[SUBJSTRLEN], email[MAILSTRLEN],
- inreply[REPYSTRLEN], date[DATESTRLEN], fromdate[DATESTRLEN],
- msgid[MSGDSTRLEN];
-
- num = 0;
- replylist = NULL;
-
- while (hashnumlookup(num, name, email, subject, inreply,
- date, fromdate, msgid) != NULL) {
- if (inreply[0] != '\0') {
- status = hashreplynumlookup(inreply, &maybereply);
- if (status != -1)
- replylist = (struct reply *)
- addreply(replylist, status, num, name, subject,
- maybereply);
- }
- num++;
- }
- }
-
- /* First, print out the threads in order by date...
- ** Each message number is appended to a thread list. Threads and individual
- ** messages are separated by a -1.
- */
-
- void crossindexthread1(hp)
- struct header *hp;
- {
- int hasreply;
- struct reply *rp;
-
- if (hp != NULL) {
- crossindexthread1(hp->left);
-
- for (hasreply = 0, rp = replylist; rp != NULL; rp = rp->next)
- if (rp->frommsgnum == hp->msgnum) {
- hasreply = 1;
- break;
- }
-
- if (!hasreply && !wasprinted(printedthreadlist, hp->msgnum)) {
- threadlist = (struct reply *)
- addreply(threadlist, hp->msgnum, hp->msgnum,
- hp->name, hp->subject, 0);
- crossindexthread2(hp->msgnum);
- threadlist = (struct reply *)
- addreply(threadlist, -1, -1, " ", " ", 0);
- }
-
- crossindexthread1(hp->right);
- }
- }
-
- /* Recursively checks for replies to replies to a message, etc.
- ** Replies are added to the thread list.
- */
-
- void crossindexthread2(num)
- int num;
- {
- struct reply *rp;
-
- for (rp = replylist; rp != NULL; rp = rp->next)
- if (rp->msgnum == num) {
- threadlist = (struct reply *)
- addreply(threadlist, rp->frommsgnum, num,
- rp->name, rp->subject, 0);
- printedlist = (struct printed *)
- markasprinted(printedthreadlist, rp->frommsgnum);
- crossindexthread2(rp->frommsgnum);
- }
- }
-
- /* Grabs the date string from a Date: header.
- */
-
- char *getmaildate(line)
- char *line;
- {
- int i;
- char *c;
- static char date[DATESTRLEN];
-
- c = (char *) strchr(line, ':');
- if ((*(c + 1) && *(c + 1) == '\n') ||
- (*(c + 2) && *(c + 2) == '\n')) {
- strcpy(date, NODATE);
- return date;
- }
- c += 2;
- while (isspace(*c))
- c++;
- for (i = 0; *c && *c != '\n' && i < DATESTRLEN; c++)
- date[i++] = *c;
- date[i] = '\0';
-
- return date;
- }
-
- /* Grabs the date string from a From article separator.
- */
-
- char *getfromdate(line)
- char *line;
- {
- int i;
- char *c;
- static char tmpdate[DATESTRLEN];
-
- for (i = 0; days[i] != NULL && (c = (char *) strstr(line, days[i]))
- == NULL; i++)
- ;
- if (days[i] == NULL)
- tmpdate[0] = '\0';
- else {
- for (i = 0; *c && *c != '\n' && i < DATESTRLEN; c++)
- tmpdate[i++] = *c;
- tmpdate[i] = '\0';
- if (tmpdate[16] != ':') {
- tmpdate[16] = ':';
- tmpdate[17] = '0';
- tmpdate[18] = '0';
- tmpdate[19] = ' ';
- tmpdate[20] = thisyear[0];
- tmpdate[21] = thisyear[1];
- tmpdate[22] = thisyear[2];
- tmpdate[23] = thisyear[3];
- tmpdate[24] = '\0';
- }
- sprintf(tmpdate, "%s %s", tmpdate, timezonestr);
- return tmpdate;
- }
-
- return tmpdate;
- }
-
- /* Grabs the name and email address from a From: header.
- ** This could get tricky; I've tried to keep it simple.
- */
-
- void getname(line, name, email)
- char *line;
- char *name;
- char *email;
- {
- int i;
- char *c;
-
- if ((c = (char *) strchr(line, '@')) == NULL) {
- if (strchr(line, '(')) {
- c = (char *) strchr(line, ':') + 1;
- while (isspace(*c))
- c++;
- for (i = 0; *c && *c != '(' && *c != ' ' &&
- *c != '\n' && i < MAILSTRLEN; c++)
- email[i++] = *c;
- email[i] = '\0';
- }
- else
- strcpy(email, NOEMAIL);
- }
- else {
- while (*c != ' ' && *c != '<')
- c--;
- c++;
- for (i = 0; *c && *c != '>' && *c != ' ' && *c != '\n' &&
- i < MAILSTRLEN;
- c++)
- email[i++] = *c;
- email[i] = '\0';
- }
-
- if (strchr(line, '<')) {
- c = (char *) strchr(line, ':') + 1;
- while (isspace(*c) || *c == '\"')
- c++;
- }
- else if (strchr(line, '('))
- c = (char *) strchr(line, '(') + 1;
- else {
- if (strcmp(email, NOEMAIL))
- strcpy(name, email);
- else
- strcpy(name, NONAME);
- return;
- }
-
- for (i = 0; *c && *c != '<' && *c != '\"' && *c != ')' &&
- *c != '(' && *c != '\n' && i < NAMESTRLEN; c++)
- name[i++] = *c;
- if (*c == '<' || *c == '(')
- name[--i] = '\0';
- else
- name[i] = '\0';
- }
-
- /* Grabs the message ID, like <...> from the Message-ID: header.
- */
-
- char *getid(line)
- char *line;
- {
- int i;
- char *c;
- static char msgid[MSGDSTRLEN];
-
- c = (char *) strchr(line, '<') + 1;
- for (i = 0; *c && *c != '>' && *c != '\n' && i < MSGDSTRLEN; c++) {
- if (*c == '\\')
- continue;
- msgid[i++] = *c;
- }
- msgid[i] = '\0';
-
- return msgid;
- }
-
- /* Grabs the subject from the Subject: header.
- */
-
- char *getsubject(line)
- char *line;
- {
- int i;
- char *c;
- static char subject[SUBJSTRLEN];
-
- c = (char *) strchr(line, ':') + 2;
- while (isspace(*c))
- c++;
- for (i = 0; *c && *c != '\n' && i < SUBJSTRLEN; c++)
- subject[i++] = *c;
- subject[i] = '\0';
- for (i--; i >= 0 && isspace(subject[i]); i--)
- subject[i] = '\0';
-
- if (subject[0] == NULL || isspace(subject[0]) || subject[0] == '\n' ||
- #ifdef RISCOS
- !strcmp(subject, "Re:"))
- #else
- !strcasecmp(subject, "Re:"))
- #endif
- strcpy(subject, NOSUBJECT);
-
- return subject;
- }
-
- /* Grabs the message ID, or date, from the In-reply-to: header.
- ** Who knows what other formats are out there...
- */
-
- char *getreply(line)
- char *line;
- {
- int i;
- char *c;
- static char reply[REPYSTRLEN];
-
- if ((c = (char *) strstr(line, "dated: ")) != NULL) {
- c += 7;
- for (i = 0; *c && *c != '.' && *c != '\n' && i < REPYSTRLEN;
- c++)
- reply[i++] = *c;
- reply[i] = '\0';
- return reply;
- }
-
- if ((c = (char *) strchr(line, '<')) != NULL ) {
- c++;
- for (i = 0; *c && *c != '>' && *c != '\n' && i < MSGDSTRLEN;
- c++) {
- if (*c == '\\')
- continue;
- reply[i++] = *c;
- }
- reply[i] = '\0';
- return reply;
- }
-
- if ((c = (char *) strstr(line, "sage of ")) != NULL) {
- c += 8;
- if (*c == '\"')
- c++;
- for (i = 0; *c && *c != '.' && *c != '\n' && *c != 'f' &&
- i < REPYSTRLEN; c++)
- reply[i++] = *c;
- reply[i] = '\0';
- if (*c == 'f')
- reply[--i] = '\0';
- return reply;
- }
-
- reply[0] = '\0';
- return reply;
- }
-